# 点点网积分脚本（playwright重构版）
import json
import os
import sys
import time
import threading
from tkinter import *
from tkinter import scrolledtext, messagebox
from tkinter import ttk
import smtplib
import imaplib
import email
import webbrowser
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from playwright.sync_api import sync_playwright

# 配置文件路径
CONFIG_DIR = 'config'
SETTINGS_FILE = os.path.join(CONFIG_DIR, 'settings.json')
COOKIE_FILE = os.path.join(CONFIG_DIR, 'bilicookie.txt')

# B站二维码登录相关URL
BILIBILI_QR_LOGIN_URL = "https://passport.bilibili.com/x/passport-login/web/qrcode/generate?source=main-fe-header"
BILIBILI_QR_POLL_URL = "https://passport.bilibili.com/x/passport-login/web/qrcode/poll"

# 全局变量用于控制任务停止
stop_flag = False
# 全局变量用于存储浏览器实例
browser = None
# 全局变量用于存储主窗口实例
root = None
# 全局变量用于存储二维码窗口实例
qr_window = None
# 全局变量用于存储浏览器无头模式设置
headless_mode = None
# 添加全局变量用于存储验证邮件的信息
verification_email_id = None
verification_email_subject = None
# 添加相关全局变量
verification_email_sent_time = None  # 记录验证邮件发送时间
verification_email_message_id = None  # 记录验证邮件的Message-ID
waiting_for_reply = False  # 是否在等待回复
monitoring_thread_started = False  # 监控线程是否已启动

# 默认参数值
DEFAULT_URL = None
DEFAULT_USER = None
DEFAULT_PASSWORD = None

# 全局变量存储用户设置
settings = {
    'url': 'https://www.idiandian.xyz/login',
    'user': DEFAULT_USER,
    'password': DEFAULT_PASSWORD,
    'smtp_server': '',
    'smtp_port': 25,
    'smtp_username': '',
    'smtp_password': '',
    'recipient_email': ''
}

def save_settings():
    """保存设置到文件"""
    try:
        os.makedirs(CONFIG_DIR, exist_ok=True)
        with open(SETTINGS_FILE, 'w', encoding='utf-8') as f:
            json.dump(settings, f, ensure_ascii=False, indent=4)
        print("\n设置已保存到文件")
    except Exception as e:
        print(f"保存设置时出错: {e}")

def load_settings():
    """从文件加载设置"""
    global settings
    try:
        if os.path.exists(SETTINGS_FILE):
            with open(SETTINGS_FILE, 'r', encoding='utf-8') as f:
                loaded_settings = json.load(f)
                # 合并默认设置和加载的设置，以防缺少某些键
                settings.update(loaded_settings)
            print("已从文件加载设置")
        else:
            # 如果设置文件不存在，创建默认设置文件
            save_settings()
    except Exception as e:
        print(f"加载设置时出错: {e}")

def open_settings_window():
    """打开配置窗口"""
    settings_window = Toplevel()
    settings_window.title("配置")
    settings_window.geometry("300x300")
    settings_window.resizable(False, False)
    
    # 将设置窗口定位到主窗口的中心
    # 获取主窗口的位置和尺寸
    root_x = root.winfo_x()
    root_y = root.winfo_y()
    root_width = root.winfo_width()
    root_height = root.winfo_height()
    
    # 计算设置窗口的位置
    settings_width = 300
    settings_height = 300
    settings_x = root_x + (root_width // 2) - (settings_width // 2)
    settings_y = root_y + (root_height // 2) - (settings_height // 2)
    
    # 设置窗口位置
    settings_window.geometry(f"+{settings_x}+{settings_y}")
    
    # 保持设置窗口置顶
    settings_window.wm_attributes("-topmost", True)
    
    # 创建标签页控件
    notebook = ttk.Notebook(settings_window)
    notebook.pack(fill=BOTH, expand=True, padx=5, pady=5)
    
    # 创建网站设置标签页
    website_frame = Frame(notebook)
    notebook.add(website_frame, text="网站设置")
    
    # 网站设置内容
    Label(website_frame, text="登录网址:").grid(row=0, column=0, padx=5, pady=5, sticky=E)
    url_entry = Entry(website_frame, width=20)
    url_entry.grid(row=0, column=1, padx=5, pady=5, sticky=W)
    url_entry.insert(0, settings['url'] or '')
    
    Label(website_frame, text="用户名:").grid(row=1, column=0, padx=5, pady=5, sticky=E)
    user_entry = Entry(website_frame, width=20)
    user_entry.grid(row=1, column=1, padx=5, pady=5, sticky=W)
    user_entry.insert(0, settings['user'] or '')
    
    Label(website_frame, text="密码:").grid(row=2, column=0, padx=5, pady=5, sticky=E)
    password_entry = Entry(website_frame, show="*", width=20)
    password_entry.grid(row=2, column=1, padx=5, pady=5, sticky=W)
    password_entry.insert(0, settings['password'] or '')
    
    # 创建通知设置标签页
    notification_frame = Frame(notebook)
    notebook.add(notification_frame, text="通知设置")
    
    # SMTP设置内容
    Label(notification_frame, text="SMTP服务器:").grid(row=0, column=0, padx=5, pady=5, sticky=E)
    smtp_server_entry = Entry(notification_frame, width=20)
    smtp_server_entry.grid(row=0, column=1, padx=5, pady=5, sticky=W)
    smtp_server_entry.insert(0, settings['smtp_server'])
    
    Label(notification_frame, text="SMTP端口:").grid(row=1, column=0, padx=5, pady=5, sticky=E)
    smtp_port_entry = Entry(notification_frame, width=20)
    smtp_port_entry.grid(row=1, column=1, padx=5, pady=5, sticky=W)
    smtp_port_entry.insert(0, settings['smtp_port'])
    
    Label(notification_frame, text="SMTP用户名:").grid(row=2, column=0, padx=5, pady=5, sticky=E)
    smtp_username_entry = Entry(notification_frame, width=20)
    smtp_username_entry.grid(row=2, column=1, padx=5, pady=5, sticky=W)
    smtp_username_entry.insert(0, settings['smtp_username'])
    
    Label(notification_frame, text="SMTP密码:").grid(row=3, column=0, padx=5, pady=5, sticky=E)
    smtp_password_entry = Entry(notification_frame, show="*", width=20)
    smtp_password_entry.grid(row=3, column=1, padx=5, pady=5, sticky=W)
    smtp_password_entry.insert(0, settings['smtp_password'])
    
    Label(notification_frame, text="收件人邮箱:").grid(row=4, column=0, padx=5, pady=5, sticky=E)
    recipient_email_entry = Entry(notification_frame, width=20)
    recipient_email_entry.grid(row=4, column=1, padx=(5, 2), pady=5, sticky=W)
    recipient_email_entry.insert(0, settings['recipient_email'])
    
    def test_email_notification():
        """测试邮件通知功能"""
        # 获取当前输入的设置值
        smtp_server = smtp_server_entry.get()
        smtp_port = smtp_port_entry.get()
        smtp_username = smtp_username_entry.get()
        smtp_password = smtp_password_entry.get()
        recipient_email = recipient_email_entry.get()
        
        # 检查必要字段是否填写
        if not all([smtp_server, smtp_port, smtp_username, smtp_password, recipient_email]):
            messagebox.showwarning("测试失败", "请填写所有SMTP设置字段")
            return
        
        try:
            # 尝试发送测试邮件
            msg = MIMEMultipart()
            msg['From'] = smtp_username
            msg['To'] = recipient_email
            msg['Subject'] = Header("点点网自动刷分工具 - 测试邮件", 'utf-8')
            
            body = "这是一封测试邮件，用于验证SMTP设置是否正确。"
            msg.attach(MIMEText(body, 'plain', 'utf-8'))
            
            # 连接SMTP服务器并发送邮件
            server = smtplib.SMTP(smtp_server, int(smtp_port))
            server.starttls()  # 启用TLS加密
            server.login(smtp_username, smtp_password)
            text = msg.as_string()
            server.sendmail(smtp_username, recipient_email, text)
            server.quit()
            
            messagebox.showinfo("测试成功", "测试邮件已成功发送！")
        except Exception as e:
            messagebox.showerror("测试失败", f"发送测试邮件时出错：\n{str(e)}")
    
    # 添加测试按钮
    test_button = Button(notification_frame, text="测试邮件", command=test_email_notification, width=10)
    test_button.grid(row=5, column=0, columnspan=2, padx=5, pady=5)
    
    def save_settings_from_ui():
        """从UI保存设置"""
        # 保存网站设置
        settings['url'] = url_entry.get()
        settings['user'] = user_entry.get()
        settings['password'] = password_entry.get()
        
        # 保存通知设置
        settings['smtp_server'] = smtp_server_entry.get()
        settings['smtp_port'] = smtp_port_entry.get()
        settings['smtp_username'] = smtp_username_entry.get()
        settings['smtp_password'] = smtp_password_entry.get()
        settings['recipient_email'] = recipient_email_entry.get()
        
        save_settings()
        settings_window.destroy()
        messagebox.showinfo("设置", "设置已保存")
    
    # 按钮框架
    button_frame = Frame(settings_window)
    button_frame.pack(fill=X, padx=10, pady=(0, 10))
    
    # 创建一个容器框架，使按钮整体居中
    button_container = Frame(button_frame)
    button_container.pack(expand=True)
    
    Button(button_container, text="保存设置", command=save_settings_from_ui, width=8).pack(side=LEFT, padx=5)
    Button(button_container, text="取消", command=settings_window.destroy, width=8).pack(side=LEFT, padx=5)

class StdoutRedirector:
    def __init__(self, text_widget):
        self.text_widget = text_widget

    def write(self, str):
        self.text_widget.configure(state='normal')
        self.text_widget.insert(END, str)
        self.text_widget.configure(state='disabled')
        # 自动滚动到底部
        self.text_widget.see(END)
        self.text_widget.update_idletasks()

    def flush(self):
        pass

def start_task():
    global stop_flag
    stop_flag = False
    start_button.config(state=DISABLED)
    stop_button.config(state=NORMAL)
    # 在新线程中运行任务，避免阻塞GUI
    task_thread = threading.Thread(target=run_main)
    task_thread.daemon = True
    task_thread.start()

def stop_task():
    """停止任务"""
    global stop_flag, waiting_for_reply, monitoring_flag
    stop_flag = True
    # 如果正在等待回复，也停止等待
    waiting_for_reply = False
    # 同时停止邮件监控线程
    monitoring_flag = False
    print("\n正在停止任务...")
    # 立即更新按钮状态
    stop_button.config(state=DISABLED)
    start_button.config(state=NORMAL)

def run_main():
    try:
        # 使用headless_mode变量的值启动浏览器
        main(settings['url'], settings['user'], settings['password'], headless_mode.get())
    except Exception as e:
        print(f'\n发生错误: {str(e)}')
    finally:
        global browser  # 只保留不可见浏览器实例
        # 确保浏览器关闭
        if 'browser' in globals() and browser:
            browser.close()
            browser = None
            print("浏览器已关闭")
            
        # 只在任务正常完成时更新按钮状态
        # 如果是通过stop_task停止的，按钮状态已在stop_task中更新
        if stop_flag:
            # 任务是被停止的，按钮状态已经更新过了
            pass
        else:
            # 任务是正常完成的
            start_button.config(state=NORMAL)
            stop_button.config(state=DISABLED)

def send_human_verification_alert():
    """发送人机验证警报邮件"""
    global verification_email_sent_time, verification_email_message_id, waiting_for_reply, monitoring_flag
    
    try:
        # 检查必要的SMTP设置是否存在
        if not all([settings['smtp_server'], settings['smtp_port'], settings['smtp_username'], 
                    settings['smtp_password'], settings['recipient_email']]):
            print("邮件设置不完整，无法发送人机验证警报")
            return False
        
        # 创建邮件
        msg = MIMEMultipart()
        msg['From'] = settings['smtp_username']
        msg['To'] = settings['recipient_email']
        msg['Subject'] = Header("点点网自动刷分工具 - 触发人机验证", 'utf-8')
        body = "您的点点网自动刷分任务已触发人机验证，请及时处理。\n" \
               "请完成人机验证后，回复此邮件以继续执行任务。\n链接:https://www.idiandian.xyz/earn-points" \
               "\n如果您不回复邮件，程序将不会自动继续运行。"
        msg.attach(MIMEText(body, 'plain', 'utf-8'))
        
        # 连接SMTP服务器并发送邮件
        server = smtplib.SMTP(settings['smtp_server'], int(settings['smtp_port']))
        server.starttls()  # 启用TLS加密
        server.login(settings['smtp_username'], settings['smtp_password'])
        text = msg.as_string()
        server.sendmail(settings['smtp_username'], settings['recipient_email'], text)
        server.quit()
        
        print("已发送人机验证警报邮件，等待用户回复...")
        print("提示：您可以在完成验证后的任何时间回复该邮件来启动任务")
        
        # 记录验证邮件发送时间
        verification_email_sent_time = time.time()
        waiting_for_reply = True
        monitoring_flag = True  # 确保监控线程处于活动状态
        
        # 启动邮件回复监控线程（仅在尚未启动时）
        start_email_reply_monitoring()
        
        return True
    except Exception as e:
        print(f"发送人机验证警报邮件时出错: {str(e)}")
        return False

def check_reply_to_verification_email():
    """检查是否有对验证邮件的回复"""
    mail = None
    try:
        # 检查必要的IMAP设置是否存在
        if not all([settings['smtp_server'], settings['smtp_username'], 
                    settings['smtp_password'], settings['recipient_email']]):
            print("邮件设置不完整，无法检查回复邮件")
            return False
            
        # 根据SMTP服务器确定IMAP服务器
        smtp_server = settings['smtp_server']
        if 'smtp.qq.com' in smtp_server:
            imap_server = 'imap.qq.com'
        elif 'smtp.163.com' in smtp_server:
            imap_server = 'imap.163.com'
        elif 'smtp.126.com' in smtp_server:
            imap_server = 'imap.126.com'
        elif 'smtp.gmail.com' in smtp_server:
            imap_server = 'imap.gmail.com'
        else:
            # 默认使用smtp服务器作为imap服务器
            imap_server = smtp_server.replace('smtp', 'imap')
            if imap_server == smtp_server:
                imap_server = 'imap.' + smtp_server.split('.')[-2] + '.' + smtp_server.split('.')[-1]
        
        # 连接到IMAP服务器
        mail = imaplib.IMAP4_SSL(imap_server, 993)
        mail.login(settings['smtp_username'], settings['smtp_password'])
        mail.select('inbox')  # 选择收件箱
        
        # 搜索最近30天的邮件以提高效率
        date_since = time.strftime("%d-%b-%Y", time.localtime(time.time() - 30*24*60*60))
        status, messages = mail.search(None, f'(SINCE {date_since})')
        if status != 'OK':
            print("搜索邮件时出错")
            return False
            
        # 获取邮件ID列表
        email_ids = messages[0].split()
        
        # 从最新的邮件开始检查
        for email_id in reversed(email_ids):
            # 获取邮件头部信息
            status, msg_data = mail.fetch(email_id, '(RFC822.HEADER)')
            if status != 'OK':
                continue
                
            # 解析邮件头部
            msg = email.message_from_bytes(msg_data[0][1])
            
            # 获取相关信息
            subject = msg.get('Subject', '')
            from_email = msg.get('From', '')
            in_reply_to = msg.get('In-Reply-To', '')
            references = msg.get('References', '')
            
            # 解码邮件主题
            try:
                subject_decoded = email.header.decode_header(subject)
                if subject_decoded and subject_decoded[0][0]:
                    if isinstance(subject_decoded[0][0], bytes):
                        subject = subject_decoded[0][0].decode(subject_decoded[0][1] or 'utf-8')
                    else:
                        subject = subject_decoded[0][0]
            except Exception as e:
                print(f"解码主题时出错: {e}")
            
            # 检查是否是来自目标邮箱的邮件
            if settings['recipient_email'] in from_email or settings['recipient_email'].split('@')[0] in from_email:
                # 检查是否是对验证邮件的回复
                is_reply = False
                
                # 方法1: 检查In-Reply-To头部
                if verification_email_message_id and verification_email_message_id in in_reply_to:
                    is_reply = True
                    
                # 方法2: 检查References头部
                elif verification_email_message_id and verification_email_message_id in references:
                    is_reply = True
                    
                # 方法3: 检查主题是否包含回复标记和关键词
                elif "人机验证" in subject and (subject.startswith("Re:") or "回复" in subject):
                    is_reply = True
                
                if is_reply:
                    # 获取完整邮件内容以检查是否已读
                    status, full_msg_data = mail.fetch(email_id, '(RFC822)')
                    if status == 'OK':
                        full_msg = email.message_from_bytes(full_msg_data[0][1])
                        # 检查是否有已读标志
                        flags = mail.fetch(email_id, 'FLAGS')[1][0]
                        if b'\\Seen' not in flags:
                            print("检测到对验证邮件的回复，准备启动任务...")
                            # 标记邮件为已读
                            mail.store(email_id, '+FLAGS', '\\Seen')
                            return True
                        else:
                            # 邮件已读，说明已经处理过了
                            pass
        
        return False
    except Exception as e:
        print(f"检查回复邮件时出错: {str(e)}")
        return False
    finally:
        # 确保正确关闭连接
        try:
            if mail:
                mail.close()
                mail.logout()
        except:
            pass

def email_reply_monitoring_thread():
    """邮件回复监控线程 - 适合长期等待"""
    global monitoring_flag, waiting_for_reply, monitoring_thread_started
    monitoring_flag = True
    
    print("邮件回复监控线程已启动")
    print("程序将持续监控验证邮件的回复，您可以在任何时间回复来启动任务")
    
    # 初始检查间隔
    check_interval = 60  # 1分钟
    
    while monitoring_flag:
        try:
            # 只有在等待回复时才检查
            if waiting_for_reply:
                print(f"检查是否有对验证邮件的回复... (检查间隔: {check_interval}秒)")
                
                # 检查是否有对验证邮件的回复
                if check_reply_to_verification_email():
                    # 在主线程中启动任务
                    root.after(0, lambda: [
                        print("检测到验证邮件回复，正在启动任务..."),
                        start_task()
                    ])
                    
                    # 停止等待回复并退出监控线程
                    waiting_for_reply = False
                    monitoring_flag = False
                    monitoring_thread_started = False  # 允许重新启动线程
                    print("邮件回复监控线程已停止")
                    return

                else:
                    # 逐渐增加检查间隔，但不超过1小时
                    if check_interval < 3600:  # 最大1小时
                        check_interval = min(check_interval * 1.1, 3600)
                        
                    # 如果等待时间很长，给出提示
                    if verification_email_sent_time:
                        elapsed_time = time.time() - verification_email_sent_time
                        if elapsed_time >  60 * 60:  # 1小时
                            print("提示：已等待超过1小时，您仍可以在完成验证后回复邮件来启动任务")
                            
            # 等待指定时间
            time.sleep(check_interval)
            
        except Exception as e:
            print(f"邮件回复监控线程出错: {str(e)}")
            # 出错时等待一段时间再重试
            time.sleep(300)  # 5分钟
    
    print("邮件回复监控线程已停止")


def start_email_reply_monitoring():
    """开始邮件回复监控"""
    global monitoring_thread_started
    # 检查监控线程是否已经启动
    if not monitoring_thread_started:
        monitoring_thread_started = True
        monitoring_thread = threading.Thread(target=email_reply_monitoring_thread)
        monitoring_thread.daemon = True
        monitoring_thread.start()

def main(url, user, password, headless=True):
    global stop_flag, browser
    # 实例化浏览器用于执行任务
    p = sync_playwright().start()
    # 使用传入的headless参数启动浏览器
    browser = p.chromium.launch(headless=headless)
    context = browser.new_context(
        viewport={'width':800,'height':600},
        # 忽略HTTPS错误，解决证书问题
        ignore_https_errors=True
    )
    context.set_default_timeout(30000)    # 默认等待30秒

    # 检查cookie文件是否存在
    if not os.path.exists(COOKIE_FILE):
        print("未找到B站cookie文件，请先点击'获取Cookie'按钮获取cookie")
        return

    # 打开并登录网站
    page = context.new_page()
    page.goto(url)
    page.locator('#username').fill(user)
    page.locator('#password').fill(password)
    page.locator('xpath=//*[@id="signupform"]/button').click()

    # 点击ok
    page.locator('xpath=/html/body/div[2]/div/div[6]/button[1]').click()

    # 获取当前积分
    pointnow = int(page.locator('#currentpoints').inner_text())
    print('任务开始前积分：{}'.format(pointnow))

    # 判断分数是否大于15万
    if pointnow > 150000:
        print('分数大于15万，无需刷分！')
        return

    # 进入任务界面
    page.goto(url.replace('/login', '/earn-points'))
    page.wait_for_timeout(3000)
    
    try:
        page.mouse.click(100, 100)
        page.get_by_text('求赞区').click()
        page.get_by_text('BL').click()
        page.get_by_text('确认提交').click()
    except Exception as e:
        # 检查是否是超时错误，这通常意味着触发了人机验证
        if "Timeout" in str(e):
            print(f"检测到超时错误，可能是触发了人机验证: {e}")
            # 发送人机验证警报邮件
            send_human_verification_alert()
            print("任务已停止，请重新开始任务...")
            # 直接返回，终止任务
            return
        else:
            # 如果是其他错误，重新抛出
            raise e

    # 开始任务
    n = 1
    while not stop_flag:
        # 检查是否需要停止任务
        if stop_flag:
            break
            
        try:
            page.get_by_text('点赞视频').click()
        except Exception as e:
             # 检查是否出现"没有更多作品啦"提示
            try:
                no_more_work_text = page.get_by_text('没有更多作品啦')
                if no_more_work_text.is_visible():
                    print("\n没有任务可以执行，任务终止。")
                    break  # 直接退出循环，停止任务
            except:
                # 即使检查"没有更多作品啦"也失败了，继续处理原始异常
                pass
            # 检查是否需要停止任务
            if stop_flag:
                break
            # 检查是否是超时错误，这通常意味着触发了人机验证
            if "Timeout" in str(e):
                print(f"检测到超时错误，可能是触发了人机验证: {e}")
                # 发送人机验证警报邮件
                send_human_verification_alert()
                print("任务已停止，请重新开始任务...")
                # 返回，停止任务执行
                return
            else:
                # 如果是其他错误，重新抛出
                raise e

        # 检查是否需要停止任务
        if stop_flag:
            break

        # 等待新页面打开并切换至视频窗口
        # 动态等待直到出现新的页面
        page.wait_for_timeout(1000)  # 先等待一小段时间
        timeout = 30000  # 最大等待时间30秒
        elapsed = 0
        while len(context.pages) < 2 and elapsed < timeout and not stop_flag:
            page.wait_for_timeout(1000)
            elapsed += 1000
            # 检查是否需要停止任务
            if stop_flag:
                break
        
        # 检查是否需要停止任务
        if stop_flag:
            break
            
        if len(context.pages) < 2:
            print("等待新页面超时，跳过此任务")
            if not page.is_closed():
                page.get_by_text('跳过这个任务').click()
            continue
            
        newpage = context.pages[1]

        # 检查是否需要停止任务
        if stop_flag:
            break

        if n == 1:
            if os.path.exists(COOKIE_FILE):
                try:
                    with open(COOKIE_FILE, 'r', encoding='utf-8') as f:
                        cookie_list = json.load(f)
                    
                    # 直接使用从文件读取的完整cookie列表
                    context.add_cookies(cookie_list)
                    newpage.wait_for_timeout(1000)
                    newpage.reload()
                    print('已添加b站cookie')
                except Exception as e:
                    print(f"添加cookie时出错: {e}")
        else:
            # 对于后续循环，添加一个小延迟以确保页面加载
            newpage.wait_for_timeout(1000)
            
        # 检查是否需要停止任务
        if stop_flag:
            break
            
        # 等待点赞按钮可点击并执行点赞
        try:
            # 等待页面加载完成
            newpage.wait_for_timeout(3000)
            
            # 检查是否需要停止任务
            if stop_flag:
                break
                
            # 点击点赞按钮
            like_button = newpage.locator('//*[@id="arc_toolbar_report"]/div[1]/div[1]/div[1]/div')
            like_button.click()
        except Exception as e:
            print(f"点赞失败: {e}")
        finally:
            # 等待点赞动画完成并关闭页面
            newpage.wait_for_timeout(2000)
            if not newpage.is_closed():
                newpage.close()

        # 检查是否需要停止任务
        if stop_flag:
            break

        # 判断任务是否成功
        page.wait_for_timeout(3000)
        try:
            fb_points = page.locator('#FBPoints').first.inner_text()
            if fb_points != '':
                page.get_by_text('跳过这个任务').click()
                page.wait_for_timeout(2000)
        except Exception as e:
            print(f"检查任务状态时出错: {e}")
            # 出错时尝试跳过任务
            try:
                page.get_by_text('跳过这个任务').click()
                page.wait_for_timeout(2000)
            except:
                pass

        # 检查是否需要停止任务
        if stop_flag:
            break

        try:
            mypoint = int(page.locator('#currentpoints').inner_text())
            print('\r点赞{}个，获得{}分，当前{}分'.format(n,mypoint-pointnow,mypoint),end='')
        except Exception as e:
            print(f"\n获取积分信息时出错: {e}")
            mypoint = pointnow

        n += 1

    print("\n任务已停止")

def check_cookie_and_website_status():
    """检查cookie有效期"""
    status_text = ""
    
    # 检查cookie有效期
    if os.path.exists(COOKIE_FILE):
        try:
            mtime = os.path.getmtime(COOKIE_FILE)
            cookie_age = time.time() - mtime
            if cookie_age < 604800:  # 7天内
                remaining_hours = (604800 - cookie_age) / 3600
                status_text += f"Cookie有效期剩余: {remaining_hours:.1f}小时"
            else:
                status_text += "Cookie已过期"
        except Exception as e:
            status_text += f"检查Cookie时出错: {str(e)}"
    else:
        status_text += "未找到Cookie文件"
    
    return status_text

def get_bilibili_cookie():
    """获取B站Cookie - 使用手动登录方式"""
    def _get_cookie_task():
        try:
            print("正在打开B站页面...")
            # 启动可见浏览器用于获取cookie
            p = sync_playwright().start()
            browser = p.chromium.launch(headless=False)  # 使用可见模式
            context = browser.new_context(
                viewport={'width': 1200, 'height': 800}
            )
            page = context.new_page()
            
            # 访问B站主页
            page.goto('https://www.bilibili.com/')
            
            # 点击头像触发登录弹窗
            page.locator('//*[@id="i_cecream"]/div[2]/div[1]/div[1]/ul[2]/li[1]/li/div/div').first.click()
            
            # 等待用户手动登录
            print("请在浏览器中手动登录B站...")
            login_detected = False
            start_time = time.time()
            timeout = 60  # 60秒超时
            
            while time.time() - start_time < timeout and not login_detected:
                try:
                    # 检查是否存在退出登录按钮，判断是否登录成功
                    logout_button_text = page.locator('//*[@id="i_cecream"]/div[2]/div[1]/div[1]/ul[2]/li[1]/div[2]/div/div/div[7]/span').inner_text(timeout=1000)
                    if logout_button_text == '退出登录':
                        print('检测到登录成功！')
                        login_detected = True
                        break
                except:
                    # 元素未找到，继续等待
                    pass
                
                # 检查页面URL是否发生变化（可能已经跳转到其他页面）
                if "passport.bilibili.com" not in page.url and page.url != "https://www.bilibili.com/":
                    # 页面已跳转，可能已登录
                    print("检测到页面跳转，可能已登录...")
                    page.wait_for_timeout(2000)
                    # 再次检查登录状态
                    try:
                        logout_button_text = page.locator('//*[@id="i_cecream"]/div[2]/div[1]/div[1]/ul[2]/li[1]/div[2]/div/div/div[7]/span').inner_text(timeout=1000)
                        if logout_button_text == '退出登录':
                            print('检测到登录成功！')
                            login_detected = True
                            break
                    except:
                        pass
                
                # 等待1秒后再次检查
                page.wait_for_timeout(1000)
            
            if login_detected:
                # 获取cookie
                blicookie = context.cookies()
                
                # 检查是否获取到关键cookie
                sessdata_cookie = [cookie for cookie in blicookie if cookie['name'] == 'SESSDATA']
                dede_userid_cookie = [cookie for cookie in blicookie if cookie['name'] == 'DedeUserID']
                
                if sessdata_cookie and dede_userid_cookie:
                    # 保存cookie到文件
                    os.makedirs(CONFIG_DIR, exist_ok=True)
                    with open(COOKIE_FILE, 'w', encoding='utf-8') as f:
                        json.dump(blicookie, f, ensure_ascii=False, indent=4)
                    
                    print('B站登录成功，已保存cookie')
                    # 更新主界面状态标签
                    root.after(0, lambda: status_label.config(text=check_cookie_and_website_status()))
                else:
                    print("未能获取到有效的登录cookie，请重新登录")
            else:
                print("登录超时或未检测到登录，请重新获取cookie")
            
            # 关闭页面
            if not page.is_closed():
                page.close()
            
        except Exception as e:
            print(f"获取B站Cookie时出错: {str(e)}")
        finally:
            # 清理资源
            try:
                if 'browser' in locals():
                    browser.close()
            except:
                pass
    
    # 在新线程中运行任务，避免阻塞GUI
    cookie_thread = threading.Thread(target=_get_cookie_task)
    cookie_thread.daemon = True
    cookie_thread.start()

def create_gui():
    # 创建主窗口
    global root, headless_mode
    root = Tk()
    root.title("自动刷分")
    root.geometry("300x600")
    root.resizable(False, False)
    
    # 设置窗口居中显示
    # 获取屏幕宽度和高度
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()
    
    # 计算窗口居中坐标
    window_width = 300
    window_height = 500
    x = (screen_width - window_width) // 2
    y = (screen_height - window_height) // 2
    
    # 设置窗口位置
    root.geometry(f"{window_width}x{window_height}+{x}+{y}")
    
    # 保持窗口置顶
    root.wm_attributes("-topmost", True)
    
    # 初始化无头模式设置为False（默认不开启无头模式）
    headless_mode = BooleanVar()
    headless_mode.set(False)
    
    # 创建状态标签
    status_frame = Frame(root)
    status_frame.pack(side=TOP, fill=X, padx=10, pady=(10, 0))
    
    global status_label
    status_label = Label(status_frame, text=check_cookie_and_website_status(), 
                         fg="blue", anchor="w")
    status_label.pack(fill=X, side=LEFT)
    
    # 添加获取Cookie按钮
    get_cookie_button = Button(status_frame, text="获取Cookie", command=get_bilibili_cookie)
    get_cookie_button.pack(side=LEFT)
    
    # 创建无头模式复选框
    headless_frame = Frame(root)
    headless_frame.pack(side=TOP, fill=X, padx=10, pady=(5, 0))
    
    headless_checkbox = Checkbutton(headless_frame, text="无头模式运行", variable=headless_mode)
    headless_checkbox.pack(side=LEFT)
    
    # 添加点点网主页链接标签
    def open_ddw_website():
        webbrowser.open("https://idiandian.xyz/r=ZXPQPC")
    
    link_label = Label(headless_frame, text="访问点点网主页", fg="blue", cursor="hand2")
    link_label.pack(side=RIGHT, padx=(0, 10))
    link_label.bind("<Button-1>", lambda e: open_ddw_website())
    
    # 创建按钮区域框架
    button_frame = Frame(root)
    button_frame.pack(side=TOP, fill=X, padx=10, pady=10)
    
    # 创建按钮容器，使按钮整体居中
    button_container = Frame(button_frame)
    button_container.pack(expand=True, fill=BOTH)
    
    # 创建按钮
    global start_button, stop_button
    start_button = Button(button_container, text="开始任务", command=start_task, width=10, height=1)
    start_button.pack(side=LEFT, padx=5)
    
    stop_button = Button(button_container, text="停止任务", command=stop_task, state=DISABLED, width=10, height=1)
    stop_button.pack(side=LEFT, padx=5)
    
    # 创建设置按钮
    settings_button = Button(button_container, text="配置", command=open_settings_window, width=10, height=1)
    settings_button.pack(side=LEFT, padx=5)
    
    # 创建文本框区域框架
    text_frame = Frame(root)
    text_frame.pack(side=BOTTOM, expand=True, fill=BOTH, padx=10, pady=(0, 10))
    
    # 创建文本框用于显示输出
    text_area = scrolledtext.ScrolledText(text_frame, wrap=WORD, state=DISABLED)
    text_area.pack(expand=True, fill=BOTH)
    
    # 重定向标准输出到文本框
    sys.stdout = StdoutRedirector(text_area)
    sys.stderr = StdoutRedirector(text_area)
    
    # 显示初始信息
    print("点点网自动点赞工具")
    print("点击'开始任务'按钮启动自动化点赞任务")
    print("点击'停止任务'按钮停止当前任务")
    print("点击'配置'按钮配置参数")
    print("点击'获取Cookie'按钮更新B站Cookie")
    print("-" * 35)
    
    # 启动GUI主循环
    root.mainloop()

if __name__ == '__main__':
    print('启动图形界面...')
    load_settings()  # 在启动GUI前加载设置
    create_gui()